package com.csaba.connector.khb;

import java.io.InputStreamReader;
import java.util.List;
import java.util.logging.Logger;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.FormField;
import net.htmlparser.jericho.FormFields;
import net.htmlparser.jericho.HTMLElementName;
import net.htmlparser.jericho.Source;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;

import com.csaba.connector.ServiceException;
import com.csaba.connector.khb.model.KHBSession;
import com.csaba.util.LoggerHelper;

public class Util implements Codes
{

	private Util()
	{
		// private constructor to avoid instantiation.
	}

	public static ScriptEngine getEngine( final KHBSession khb ) throws ServiceException
	{
		if ( khb.isRemotePropertySet(RP_JAVASCRIPT_ENGINE) )
		{
			return (ScriptEngine) khb.getRemoteProperty(RP_JAVASCRIPT_ENGINE);
		}

		final ScriptEngineManager mgr = new ScriptEngineManager();
		final ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");

		try
		{
			jsEngine.eval(new InputStreamReader(Util.class.getResourceAsStream("sha1.js")));
		}
		catch ( final ScriptException e )
		{
			throw new ServiceException("Failed to initialized JavaScript content.", e);
		}
		khb.setRemoteProperty(RP_JAVASCRIPT_ENGINE, jsEngine);
		return jsEngine;
	}

	private static String invokeStringMethod( final KHBSession khb, final String method, final String parameter )
			throws ServiceException
	{
		final ScriptEngine engine = getEngine(khb);

		try
		{
			return (String) engine.eval(method + "('" + parameter + "')");
		}
		catch ( final ScriptException e )
		{
			throw new ServiceException("Failed to process JavaScript " + method + "() invocation.", e);
		}
	}

	public static String escapeIt( final KHBSession khb, final String concatinated ) throws ServiceException
	{
		return invokeStringMethod(khb, "escapeit", concatinated);
	}

	public static String tellNonStandard( final KHBSession khb, final String concatinated ) throws ServiceException
	{
		return invokeStringMethod(khb, "tellnonstandard", concatinated);
	}

	public static String hexSha1( final KHBSession khb, final String escaped ) throws ServiceException
	{
		return invokeStringMethod(khb, "hex_sha1", escaped);
	}

	private final static Logger logger = LoggerHelper.getDefaultLogger();

	public static NameValuePair[] extractForm( final String html, final String formId ) throws ServiceException
	{
		return extractForm(html, formId, null);
	}

	public static NameValuePair[] extractForm( final String html, final String formId, final NameValuePair[] additionals )
			throws ServiceException
	{
		final Source source = new Source(html);
		Element myForm = null;
		final List<Element> formElements = source.getAllElements(HTMLElementName.FORM);
		for ( final Element formElement : formElements )
		{
			final String formName = formElement.getAttributes().getValue("name");
			logger.finer("Looking for " + formId + " but found form=" + formName);
			if ( formId.equals(formName) )
			{
				myForm = formElement;
				break;
			}
		}

		if ( myForm == null )
			throw new ServiceException("Missing form in the HTML result. Form ID: " + formId);

		final FormFields formFields = myForm.getFormFields();
		final String[] labels = formFields.getColumnLabels();
		NameValuePair[] result = null;
		if ( additionals != null )
		{
			result = new NameValuePair[labels.length + additionals.length];
			for ( int i = labels.length; i < result.length; i++ )
			{
				result[i] = additionals[i - labels.length];
			}
		}
		else
		{
			result = new NameValuePair[labels.length];
		}
		for ( int i = 0; i < labels.length; i++ )
		{
			final FormField field = formFields.get(labels[i]);
			if ( field.getValues().size() >= 1 )
			{
				result[i] = new BasicNameValuePair(labels[i], field.getValues().get(0));
			}
			else if ( field.getPredefinedValues().size() >= 1 )
			{
				result[i] = new BasicNameValuePair(labels[i], field.getPredefinedValues().iterator().next());
			}
			else
			{
				result[i] = new BasicNameValuePair(labels[i], "");
				logger.warning("Form field '" + labels[i] + "'in form '" + formId + "'has no meaningful value for it.");
			}
		}
		return result;
	}

	public static NameValuePair getPair( final NameValuePair[] pairs, final String name ) throws ServiceException
	{
		for ( final NameValuePair pair : pairs )
		{
			if ( pair.getName().equals(name) )
				return pair;
		}
		throw new ServiceException("Missing form attribute: " + name);
	}

	public static void setPairValue( final NameValuePair[] pairs, final String name, final String value )
			throws ServiceException
	{
		for ( int i = 0; i < pairs.length; i++ )
		{
			NameValuePair pair = pairs[i];
			if ( pair.getName().equals(name) )
			{
				pair = new BasicNameValuePair(pair.getName(), value);
				pairs[i] = pair;
				return;
			}
		}
		throw new ServiceException("Missing form attribute: " + name);
	}

	/**
	 * Test text: The quick brown fox jumps over the lazy dog.
	 * str2bin-bin2hex: 54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c61737920646f672e
	 * hex_sha1:408d94384216f890ff7a0c3528e8bed1e0b01621
	 *          408d94384216f890ff7a0c3528e8bed1e0b01621
	 * Test text: sign_this=5BE4366252D3|logintype=e-bank SMS azonosítással|lite_password=UbSRhn
	 * str2bin-bin2hex: 7369676e5f746869733d3542453433363632353244337c6c6f67696e747970653d652d62616e6b20534d5320617a6f6effffed74e17373616c7c6c6974655f70617373776f72643d55625352686e0000
	 * hex_sha1:86ea286f919ca720a1c06af618ea2c2d868fd710
	 * 			86ea286f919ca720a1c06af618ea2c2d868fd710
	 *          419cc130f2e97f36e93fae1b0c86e69dda9e1525
	 *          fdf067c77925f42d92785371c4b511b4d6d9e8e8
	*/
	public static void main( final String[] args ) throws ServiceException
	{
		final KHBSession khb = new KHBSession();
		System.out.println(hexSha1(khb,
				"sign_this=5BE4366252D3|logintype=e-bank SMS azonosítással|lite_password=UbSRhn"));
		System.out.println(hexSha1(khb, "The quick brown fox jumps over the lazy dog."));

	}

}
